February 01, 2020
redux-saga는 thunk 다음으로 많이 사용하는 비동기 작업 관련 미들웨어이다. thunk는 함수 형태의 액션을 디스패치하여 미들웨어에서 해당 함수에 스토어의 dispatch와 getState를 파라미터로 넣어서 사용하는 원리 saga는 조금 더 까다로운 상황에서 유용하다
redux-saga에서는 ES6의 제너레이터 함수라는 문법을 사용한다. 보통 일반적인 상황에서는 많이 사용되지 않는다. 이 문법의 핵심 기능은 함수를 작성할 때 함수를 특정 구간에 멈춰 놓을 수도 있고, 원할떄 다시 돌아가게 할 수도 있다.
function* generatorFunction() {
console.log('하이하이');
yield 1;
console.log('제너레이터');
yield 2;
console.log('function');
yield 3;
return 4;
)
제너레이터 함수를 만들 때는 function* 키워드를 사용한다.
제너레이터 생성
const generator = generatorFunction()
제너레이터 함수를 호출했을 때 반환되는 객체를 제너레이터라고 부른다.
실행
gernator.next()
gernator.next()
gernator.next()
제너레이터가 처음 만들어지면 함수의 흐름은 멈춰 있는 상태이다. next()가 호출되면 다음 yield가 있는 곳까지 호출하고 다시 함수가 멈춘다. 제너레이터 함수를 사용하면 함수를 도중에 멈출 수도 있고, 순차적으로 여러 값을 반환시킬 수 있다. next 함수에 파라미터를 넣으면 제너레이터 함수에서 yield를 사용하여 해당 값을 조회할 수 있다.
npm install redux-saga
import { createAction, handleActions } from 'redux-actions'
import { delay, put, takeEvery, takeLatest } from 'redux-saga/effects'
const INCREASE = 'counter/INCREASE'
const DECREASE = 'counter/DECREASE'
const INCREASE_ASYNC = 'counter/INCREASE_ASYNC'
const DECREASE_ASYNC = 'counter/DECREASE_ASYNC'
export const increase = createAction(INCREASE)
export const decrease = createAction(DECREASE)
// ㅁ우스 클릭 이벤트가 payload 안에 들어가지 않도록 () => undefined를 두번째 파라미터로 넣어주기
export const increasAsync = createAction(INCREASE_ASYNC, () => undefined)
export const decreasAsync = createAction(DECREASE_ASYNC, () => undefined)
function* increaseSaga() {
yield delay(1000) // 1초 기다리기
yield put(increase()) // 특정 액션 디스패치
}
function* decreaseSaga() {
yield delay(1000) // 1초 기다리기
yield put(decrease()) // 특정 액션 디스패치
}
export function* counterSaga() {
// takeEvery는 들어오는 모든 액션에 대해 특정 작업을 처리
yield takeEvery(INCREASE_ASYNC, increaseSaga)
// takelatest는 기존에 진행 중이던 작업이 있다면 취소 처리하고 마지막으로 실행된 작업만 수행
yield takeLatest(DECREASE_ASYNC, decreaseSaga)
}
const initialState = 0
const counter = handleActions(
{
[INCREASE]: state => state + 1,
[DECREASE]: state => state - 1,
},
initialState
)
export default counter
루트 리듀서를 만든것처럼 루트 사가 만들어주기
import { combineReducers } from 'redux'
import { all } from 'redux-saga/effects'
import counter, { counterSaga } from './counter'
import sample from './sample'
import loading from './loading'
const rootReducer = combineReducers({
counter,
sample,
loading,
})
export function* rootSaga() {
//all 함수는 여러 사가를 합쳐 주는 역할
yield all([counterSaga()])
}
export default rootReducer
index.js에 적용
import rootReducer, { rootSaga } from './modules'
import { createLogger } from 'redux-logger'
import ReduxThunk from 'redux-thunk'
import createSagaMiddleware from 'redux-saga'
const logger = createLogger()
const sagaMiddleware = createSagaMiddleware()
const store = createStore(
rootReducer,
applyMiddleware(logger, ReduxThunk, sagaMiddleware)
)
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)
serviceWorker.unregister()
리덕스 개발자 도구 설치
npm install redux-devtools-extension